/* Copyright (C) 2004,2005  The DESIROS Team
    desiros.dev@gmail.com

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; either version 2
   of the License, or (at your option) any later version.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
   USA. 
 */


#include <klibc.h>
#include <process.h>
#include <klibc.h>
#include <uvmm.h>
#include <debug.h>
#include <mm.h>
#include <physmem.h>
#include <gdt.h>
#include <io.h>
#include <kerrno.h>
#include <schedule.h>

#define __PLIST__

#include <process.h>

int  process_set_address_space(struct process *proc,
					struct uvmm_as *new_as)
{
  
  proc->address_space = new_as;

  return 0 ;
}


struct uvmm_as *
process_get_address_space(const struct process *proc)
{
  return proc->address_space;
}


int process_get_state(const struct process *proc){

  return proc->state ;

}
int count ;
int process_copy(struct process *proc){


       __u32 pd = NULL ;
 
       int pid,i;
       __u32* stack_ptr;
	struct uvmm_as *new_as;
        
	asm("mov (%%ebp), %%eax; mov %%eax, %0" : "=m" (stack_ptr) : );

        pid = 1;
	while (p_list[pid].state != PROC_STOPPED && pid++ < MAXPID);
	if (p_list[pid].state != PROC_STOPPED ) {
		kprintf("PANIC: not enough slot for processes\n");
		return -1 ;
	}
 /*
        count++;
        if(count > 2){
        for(i  = 0; i < 21 ;i++)
           kprintf("indx = %i cont = %x \n", i, stack_ptr[i]);
         while(1);
        }
*/



         memcpy(&p_list[pid], proc, sizeof(struct process) );
 

        p_list[pid].regs.eip = stack_ptr[16]  ;
        p_list[pid].regs.esp = stack_ptr[19];
        p_list[pid].regs.eax = 0 ; /* Children return 0;*/
        p_list[pid].regs.ebp = stack_ptr[10];

        p_list[pid].regs.ss = 0x33;
        p_list[pid].kstack.ss0 = 0x18;
        p_list[pid].regs.cs = 0x23; 

        /* Create a new stack for the kernel */
        __u32 kstack = kvmm_alloc(1, KVMM_MAP);  
        p_list[pid].kstack.esp0 = kstack  + PAGE_SIZE;

        p_list[pid].pid = pid;
        p_list[pid].parent_pid = proc->pid;

       
	pd = (__u32 ) paging_pd_create();
   
        if(pd == NULL ){
         debug();
         while(1);      
       }
           
        int ret = paging_copy_user_space(pd ,proc->regs.cr3 );
      
       if(ret != OK ){
         debug();
         while(1);      
       } 
 
        p_list[pid].regs.cr3 = (__u32) pd;

     /*Duplicate the address space */
    new_as= uvmm_duplicate_as(proc->address_space ,&p_list[pid]);
    
    if(new_as == NULL ){
         debug();
         while(1);      
       }

    process_set_address_space(&p_list[pid], new_as);

  /*Copy user stack */
  __u32 stack_size =   p_list[pid].regs.ebp - p_list[pid].regs.esp ;
  __u32* cur_ustack = (__u32*) kmalloc( PAGE_SIZE ,1); 
  __u32* parent_ustack = (__u32*) p_list[pid].regs.esp ;

    memmove(cur_ustack ,parent_ustack , PAGE_SIZE  );

    /*Load new page directory*/
    paging_load_PD(p_list[pid].regs.cr3);

 
    sti;    

    memmove( parent_ustack  ,cur_ustack , PAGE_SIZE);

    paging_load_PD(proc->regs.cr3);
    kfree((__u32)cur_ustack);
   
   /*That for last so that the process 
    is not loaded during an interruption */
    p_list[pid].state = PROC_READY;
    num_proc++;


  return pid ;

}


